package model;


import java.util.*;
import java.util.concurrent.Callable;
public class MonteCarloMulti implements Callable<Double> {

	
	private String CallPutFlag;
	private double S;
	private double X; 
	private double T; 
	private double r; 
	private double b; 
	private double v; 
	private int nSteps; 
	private int nSimulations;
	
	/**
	 * Constructeur qui initialise tous les parametres necessaire
	 * @param CallPutFlag
	 * @param S
	 * @param X
	 * @param T
	 * @param r
	 * @param b
	 * @param v
	 * @param nSteps
	 * @param nSimulations
	 */
	public MonteCarloMulti(String CallPutFlag, double S, double X, double T,
			double r, double b, double v, int nSteps, int nSimulations) {
		super();
		this.CallPutFlag = CallPutFlag;
		this.S = S;
		this.X = X;
		this.T = T;
		this.r = r;
		this.b = b;
		this.v = v;
		this.nSteps = nSteps;
		this.nSimulations = nSimulations;
	}

	
	/**
	 * Methode qui calcule la valeur final
	 * @return double
	 */
	public double MonteCarloStandardOption ()
	{
		double dt = 0.0, St = 0.0;
		double Sum = 0.0, Drift = 0.0, vSqrdt = 0.0;
		int i, j = 0, z = 0;
		double MonteCarloValue;
		
		Random randomno = new Random();
		
		dt = T/nSteps;
		Drift = (b - ((Math.pow(v, 2))/ 2)) * dt;
		vSqrdt = v * Math.sqrt(dt);
		
		if (CallPutFlag.equalsIgnoreCase("C"))
		{
			z = 1;
		}
		else if (CallPutFlag.equalsIgnoreCase("P"))
		{
			z = -1;
		}
		
		for (i=1; i<nSimulations; i++)
		{
			St = S;
			for (j=1; j<nSteps; j++)
			{
				St = St * Math.exp(Drift + vSqrdt * randomno.nextGaussian());
			}
			Sum = Sum + Math.max(z * (St - X), 0);
		}
		
		MonteCarloValue = Math.exp(-r * T) * (Sum / nSimulations);
		return MonteCarloValue;
	}

	@Override
	/**
	 * Methode call qui va retourner la valeur obtenue
	 * @return double
	 */
	public Double call() throws Exception {
		// TODO Auto-generated method stub
		double dd = MonteCarloStandardOption();
		return dd;
	}
}
